using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using AjaxControlToolkit;

#region Assembly level WebResource Attribute
[assembly: System.Web.UI.WebResource("AnimatedSiteMapControl.AnimatedSiteMapMenuBehavior.js", "text/javascript")]
#endregion

namespace AnimatedSiteMapControl
{
    [ToolboxData("<{0}:AnimatedSiteMapMenu runat=server></{0}:AnimatedSiteMapMenu>")]
    [Designer(typeof(AnimatedSiteMapDesigner))]
    public class AnimatedSiteMapMenu : System.Web.UI.ScriptControl
    {
        #region Private fields

        private string _urlMap = null;
        private string _targetContainer = string.Empty;
        private float _initialAnimSpeed = 1;
        private float _navAnimSpeed = 1;
        private string _leafNodeCss = string.Empty;
        private string _centreNodeCss = string.Empty;
        private string _linkCss = string.Empty;
        private string _backLinkText = string.Empty;
        private string _backLinkCss = string.Empty;
        private string _lineColour = string.Empty;
        private int _lineThickness = 1;

        #endregion

        #region OnLoad event

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            //NOTE: format of each Node entry is:
            //      TITLE | URL | PARENT TITLE | HasChildren
            //      where TITLE is used as the key to locate and identify parent nodes. May require an ID of sorts later but we'll see....
            sb.AppendFormat("{0}", SerialiseNodeDetail(SiteMap.RootNode.Title, SiteMap.RootNode.Url, string.Empty, true));  // assume root always has children

            if (SiteMap.RootNode.HasChildNodes)
            {
                IEnumerator rootNodesChildrenEnumerator = SiteMap.RootNode.ChildNodes.GetEnumerator();
                while (rootNodesChildrenEnumerator.MoveNext())
                {
                    SiteMapNode sNode = (SiteMapNode)rootNodesChildrenEnumerator.Current;
                    GenerateNodeList(sNode, sb, SiteMap.RootNode);
                }
            }

            _urlMap = sb.ToString();
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// The target container element ID whete the animated SiteMap is placed and constrained.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Behavior")]
        public string TargetContainer
        {
            get { return _targetContainer; }
            set { _targetContainer = value; }
        }

        /// <summary>
        /// The animation speed of the inital display of the site map nodes
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Behavior")]
        public float InitialAnimationSpeed
        {
            get { return _initialAnimSpeed; }
            set { _initialAnimSpeed = value; }
        }

        /// <summary>
        /// The animation speed used when clicking on a node that has sub nodes (ie. navigating the heirarchy)
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Behavior")]
        public float NavigateAnimationSpeed
        {
            get { return _navAnimSpeed; }
            set { _navAnimSpeed = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        public string LeafNodeCssClass
        {
            get { return _leafNodeCss; }
            set { _leafNodeCss = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        public string CentreNodeCssClass
        {
            get { return _centreNodeCss; }
            set { _centreNodeCss = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        public string LinkCssClass
        {
            get { return _linkCss; }
            set { _linkCss = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        public string BackLinkText
        {
            get { return _backLinkText; }
            set { _backLinkText = value; }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        public string BackLinkCssClass
        {
            get { return _backLinkCss; }
            set { _backLinkCss = value; }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        public string LineColour
        {
            get { return _lineColour; }
            set { _lineColour = value; }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        public int LineThickness
        {
            get { return _lineThickness; }
            set { _lineThickness = value; }
        }
        #endregion

        #region GenerateNodeList method

        /// <summary>
        /// Generates a string which is a serialised list of node properties.
        /// Format is:
        /// -----------------Node-----------------------|-----------------Node-----------------------|
        /// Title | Url | ParentNodeTitle | HasChildren ; Title | Url | ParentNodeTitle | HasChildren
        /// 
        /// Basically, each set of node details is separated by a semi colon ( ; ), and each detail within that set
        /// is separated by a 'pipe' ( | )
        /// </summary>
        /// <param name="node"></param>
        /// <param name="currentList"></param>
        /// <param name="parentNode"></param>
        private void GenerateNodeList(SiteMapNode node, StringBuilder currentList, SiteMapNode parentNode)
        {
            if (node.HasChildNodes)
            {
                currentList.AppendFormat(";{0}", SerialiseNodeDetail(node.Title, node.Url, parentNode.Title,true));
                foreach (SiteMapNode childNode in node.ChildNodes)
                    GenerateNodeList(childNode, currentList, node);
            }
            else
                currentList.AppendFormat(";{0}", SerialiseNodeDetail(node.Title, node.Url, parentNode.Title, false));

        }

        /// <summary>
        /// Common method to generate a serialised item of node details
        /// </summary>
        /// <param name="title"></param>
        /// <param name="url"></param>
        /// <param name="parentTitle"></param>
        /// <param name="hasChildren"></param>
        /// <returns></returns>
        private string SerialiseNodeDetail(string title, string url, string parentTitle, bool hasChildren)
        {
            return string.Format("{0}|{1}|{2}|{3}", title, url, parentTitle, hasChildren.ToString().ToLower());
        }

        #endregion

        #region IScriptControl Members

        protected override IEnumerable<ScriptDescriptor>  GetScriptDescriptors()
        {
 	         //base.GetScriptDescriptors();
            ScriptComponentDescriptor des = new ScriptComponentDescriptor("AnimatedSiteMapMenu.AnimatedSiteMapMenuBehavior");
            des.AddProperty("UrlMap", _urlMap);
            des.AddProperty("TargetContainer", _targetContainer);
            des.AddProperty("InitialAnimationSpeed", _initialAnimSpeed);
            des.AddProperty("NavigateAnimationSpeed", _navAnimSpeed);
            des.AddProperty("LeafNodeCssClass", _leafNodeCss);
            des.AddProperty("CentreNodeCssClass", _centreNodeCss);
            des.AddProperty("LinkCssClass", _linkCss);
            des.AddProperty("BackLinkCssClass", _backLinkCss);
            des.AddProperty("BackLinkText", _backLinkText);
            des.AddProperty("LineColour", _lineColour);
            des.AddProperty("LineThickness", _lineThickness);
            des.AddProperty("id", this.ID);

            yield return des;
        }

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            const string toolkitAssembly = "AjaxControlToolkit";   // The name of the AJAX Control toolkit assembly
            const string thisAssembly = "AnimatedSiteMapControl";   // The name of this assembly, that contains the SiteMap behavior script

            List<string> assemblyList = new List<string>();
            List<string> nameList = new List<string>();

            assemblyList.Add(toolkitAssembly);
            nameList.Add("AjaxControlToolkit.ExtenderBase.BaseScripts.js");

            assemblyList.Add(toolkitAssembly);
            nameList.Add("AjaxControlToolkit.Common.Common.js");

            assemblyList.Add(toolkitAssembly);
            nameList.Add("AjaxControlToolkit.Compat.Timer.Timer.js");

            assemblyList.Add(toolkitAssembly);
            nameList.Add("AjaxControlToolkit.Animation.Animations.js");

            assemblyList.Add(thisAssembly);
            nameList.Add("AnimatedSiteMapControl.AnimatedSiteMapMenuBehavior.js");

            List<ScriptReference> sList = new List<ScriptReference>(assemblyList.Count);
            for (int cnt = 0; cnt < assemblyList.Count; cnt++)
            {
                ScriptReference sref = new ScriptReference();
                sref.Assembly = assemblyList[cnt];
                sref.Name = nameList[cnt];
                sList.Add(sref);
            }

            //List<ScriptReference> sList = new List<ScriptReference>(2);

            //ScriptReference sref = new ScriptReference();
            //sref.Assembly = "AjaxControlToolkit";
            //sref.Name = "AjaxControlToolkit.ExtenderBase.BaseScripts.js";
            //sList.Add(sref);

            //sref = new ScriptReference();
            //sref.Assembly = "AjaxControlToolkit";
            //sref.Name = "AjaxControlToolkit.Common.Common.js";
            //sList.Add(sref);

            //sref = new ScriptReference();
            //sref.Assembly = "AjaxControlToolkit";
            //sref.Name = "AjaxControlToolkit.Compat.Timer.Timer.js";
            //sList.Add(sref);

            //sref = new ScriptReference();
            //sref.Assembly = "AjaxControlToolkit";
            //sref.Name = "AjaxControlToolkit.Animation.Animations.js";
            //sList.Add(sref);

            //sref = new ScriptReference();
            //sref.Assembly = "Prototype";
            //sref.Name = "Prototype.Components.AnimatedSiteMapMenu.AnimatedSiteMapMenuBehavior.js";
            //sList.Add(sref);

            return sList;
        }

        #endregion

    }
}
